package com.avit.tv.kui;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.avit.tv.kui.base.BaseFocusLayout;
import com.avit.tv.kui.utils.Log;

import java.lang.ref.WeakReference;

/**
 * 自定义跑马灯，分为横向与纵向
 * 适合单独控件布局，不适合用在组件中并成为某个组件的子控件
 * @author like
 * @date 2020/6/18
 */
public class AvitMarqueeView extends BaseFocusLayout {

    private String textValue;
    private int textSize;
    private int textColor;
    private int repeatCount;
    private int speed;
    private int contentGravity;
    private int animationOrientation;
    private Rect childRect;
    private Rect hostRect;
    private Paint childPaint;

    private static final int CANVAS_HANDLER = 0x0001; // 跑马灯绘制的 msg.what
    private static final int RELEASE_HANDLER = 0x000f; // 跑马灯停止的 msg.what
    public static final int REPEAT_MAX = Integer.MAX_VALUE;// 跑马灯最大跑的次数 [默认最大]
    public static final int REPEAT_MIN = 1;// 跑马灯最小跑的次数
    public static final int SOFT_SPEED = 3; // 适中的speed

    //-----------------------------------------
    // 纵向跑马灯停止的时候所显示的位置
    public static final int CONTENT_CENTER = 0;
    public static final int CONTENT_START = 1;
    public static final int CONTENT_END = 2;
    //-----------------------------------------



    /**
     * 横向滚动
     */
    public static final int ANIMATION_HORIZONTAL = 0;
    /**
     * 纵向滚动
     */
    public static final int ANIMATION_VERTICAL = 1;

    private CanvasHandler handler;

    private float baseLineY;

    private boolean isStartMarquee;


    public AvitMarqueeView(@NonNull Context context) {
        super(context);
    }

    public AvitMarqueeView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public AvitMarqueeView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void initView(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.AvitMarqueeView, defStyleAttr, 0);
        textValue = typedArray.getString(R.styleable.AvitMarqueeView_text);
        textSize = typedArray.getDimensionPixelSize(R.styleable.AvitMarqueeView_text_size, DEFAULT_SIZE);
        textColor = typedArray.getColor(R.styleable.AvitMarqueeView_text_color, Color.WHITE);
        repeatCount = typedArray.getInt(R.styleable.AvitMarqueeView_repeat_count, REPEAT_MAX);
        contentGravity = typedArray.getInt(R.styleable.AvitMarqueeView_content_gravity, CONTENT_START);
        animationOrientation = typedArray.getInt(R.styleable.AvitMarqueeView_animation_orientation, ANIMATION_HORIZONTAL);
        speed = typedArray.getInt(R.styleable.AvitMarqueeView_speed, SOFT_SPEED);
        isStartMarquee = typedArray.getBoolean(R.styleable.AvitMarqueeView_is_start_marquee, false);
        typedArray.recycle();
    }

    @Override
    protected void initContent(Context context) {
        hostRect = new Rect();
        if (TextUtils.isEmpty(textValue)) return;
        childRect = new Rect();
        childPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        childPaint.setTextAlign(Paint.Align.LEFT);
        childPaint.setColor(textColor);
        childPaint.setTextSize(textSize);
        childPaint.getTextBounds(textValue, 0, textValue.length() - 1, childRect);
        float measureText = childPaint.measureText(textValue);
        if (handler == null)
            handler = new CanvasHandler(this);
        handler.initParams(Math.round(measureText), speed);
        int textHeight = Math.abs(childRect.top) + Math.abs(childRect.bottom);
        baseLineY = Math.abs(childPaint.ascent() + childPaint.descent()) / 2;
        setMinimumHeight(textHeight);
    }

    /**
     * 初始化开始的点
     */
    private void initStartPoint() {
        if (null == handler) return;
        int line = Math.round(baseLineY);
        switch (contentGravity) {
            case CONTENT_CENTER:
                if (isAnimationHorizontal()) {
                    Log.e(this, "horizontal is not support gravity set");
                    handler.setStart(0);
                } else
                    handler.setStart(line + getHeight() / 2);
                break;
            case CONTENT_START:
                if (isAnimationHorizontal())
                    handler.setStart(0);
                else
                    handler.setStart(3 * line);
                break;
            case CONTENT_END:
                if (isAnimationHorizontal()) {
                    Log.e(this, "horizontal is not support gravity set");
                    handler.setStart(0);
                } else
                    handler.setStart(getHeight() - line);
                break;
        }
    }

    @Override
    protected void insertView() {
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (!isStartMarquee) {
            canvas.drawText(textValue, handler.getStart(), baseLineY + getHeight() / 2f, childPaint);
            return;
        }
        if (isAnimationHorizontal()) {
            canvas.drawText(textValue, handler.getStart(), baseLineY + getHeight() / 2f, childPaint);
            if (childRect.right > getMeasuredWidth() && !handler.isReleased)
                handler.startHanlder();
        } else {
            canvas.drawText(textValue, 0, handler.getStart(), childPaint);
            if (!handler.isReleased)
                handler.startHanlder();
        }
        if (repeatCount <= 0) {
            handler.repeateFinish();
        }

    }


    /**
     * 设置文字
     *
     * @param textValue
     */
    public void setTextValue(String textValue) {
        this.textValue = textValue;
        initContent(getContext());
    }

    /**
     * 设置字体大小
     *
     * @param textSize
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
        childPaint.setTextSize(textSize);
        initContent(getContext());
    }

    /**
     * 设置字体颜色
     *
     * @param textColor
     */
    public void setTextColor(int textColor) {
        this.textColor = textColor;
        childPaint.setColor(textColor);
        initContent(getContext());
    }


    /**
     * 设置重复次数
     *
     * @param repeatCount
     */
    public void setRepeatCount(int repeatCount) {
        this.repeatCount = repeatCount;
        initContent(getContext());
    }

    /**
     * 设置速度
     *
     * @param speed 最好的范围为 1~10
     */
    public void setSpeed(int speed) {
        this.speed = speed;
        initContent(getContext());
    }

    /**
     * 设置文字起始位置【如果纵向，则为上中下，如果横向，则为左中右】
     *
     * @param contentGravity
     */
    public void setContentGravity(int contentGravity) {
        this.contentGravity = contentGravity;
        initContent(getContext());
    }

    /**
     * 设置是纵向跑马灯还是横向跑马灯
     *
     * @param animationOrientation
     */
    public void setAnimationOrientation(int animationOrientation) {
        this.animationOrientation = animationOrientation;
        initContent(getContext());
    }

    public void setStartMarquee(boolean startMarquee) {
        isStartMarquee = startMarquee;
        if (startMarquee && handler != null) handler.startHanlder();
        else handler.relese();
    }

    /**
     * 获取文字
     *
     * @return
     */
    public String getTextValue() {
        return TextUtils.isEmpty(textValue) ? "" : textValue;
    }

    private static final class CanvasHandler extends Handler {

        private int end;
        private float start;
        private WeakReference<AvitMarqueeView> marqueeViewWeakReference;
        private int speed;
        private int tempStart;
        private boolean isReleased;
        private int count = 0;

        public CanvasHandler(AvitMarqueeView avitMarqueeView) {
            this.marqueeViewWeakReference = new WeakReference<>(avitMarqueeView);
        }

        public void initParams(float end, int speed) {
            this.end = Math.round(end);
            this.speed = Math.max(speed, 0);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (marqueeViewWeakReference == null || null == marqueeViewWeakReference.get()) return;
            if (msg.what == CANVAS_HANDLER) {
                start -= (1 + speed);
                marqueeViewWeakReference.get().invalidate();
                if (marqueeViewWeakReference.get().isAnimationHorizontal()) {
                    if (start + end < 0) {
                        start = marqueeViewWeakReference.get().hostRect.right;
                    }
                    repeatHorizontal();
                } else {
                    if (start < -marqueeViewWeakReference.get().baseLineY) {
                        start = marqueeViewWeakReference.get().baseLineY + marqueeViewWeakReference.get().getHeight();
                    }
                    repeatVertical();
                }
            } else if (msg.what == RELEASE_HANDLER) {
                removeMessages(CANVAS_HANDLER);
                removeMessages(RELEASE_HANDLER);
            }
        }

        public void startHanlder() {
            isReleased = false;
            removeMessages(CANVAS_HANDLER);
            sendEmptyMessage(CANVAS_HANDLER);
        }

        public void repeateFinish() {
            start = tempStart;
            isReleased = true;
            marqueeViewWeakReference.get().invalidate();
        }

        public void relese() {
            removeMessages(CANVAS_HANDLER);
            removeMessages(RELEASE_HANDLER);
        }

        public float getStart() {
            return start;
        }

        public void setStart(int start) {
            this.tempStart = start;
            this.start = start;
        }

        public int getTempStart() {
            return tempStart;
        }

        private void repeatHorizontal() {
            if (start > 0 && start - 1 - speed <= 0)
                marqueeViewWeakReference.get().repeatCount -= 1;
        }

        private void repeatVertical() {
            if (start > tempStart && start - 1 - speed <= tempStart)
                marqueeViewWeakReference.get().repeatCount -= 1;
        }
    }


    private boolean isAnimationHorizontal() {
        return animationOrientation == ANIMATION_HORIZONTAL;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initStartPoint();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        hostRect.left = left;
        hostRect.right = right;
        hostRect.top = top;
        hostRect.bottom = bottom;
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (handler!=null){
            handler.removeCallbacksAndMessages(null);
            handler = null;
        }
    }
}
